#pragma once

#include <iostream>
#include <cerrno>
#include <queue>
#include <mutex>
#include <sys/types.h>
#include <sys/socket.h>
#include "include/Protocol.hpp"
#include "include/CalculateService.hpp"
#include "include/Log.hpp"
#include "Common.hpp"
#include "ConnectionFactory.hpp"

class EventHandler
{
public:
    EventHandler()
    {}

    static void acceptForSelf(Connection* conn)
    {
        errno = 0;
        while(true)
        {
            std::lock_guard<std::mutex> lock(*conn->_reactorFrom->getMutex());
            int efd = conn->_reactorFrom->getEfd();
            uint64_t cnt;
            int n = ::read(efd, &cnt, sizeof(cnt));
            if(n > 0)
            {
                int connfd = conn->_reactorFrom->popEventQueue();
                setNonBlock(connfd);
                auto reader = std::bind(&EventHandler::read, std::placeholders::_1);
                auto writer = std::bind(&EventHandler::write, std::placeholders::_1);
                auto excepter = std::bind(&EventHandler::except, std::placeholders::_1);
                conn->_reactorFrom->addConnection(ConnectionFactory::createNormalConnection(
                    connfd, reader, writer, excepter, EPOLLIN|EPOLLET, conn->_reactorFrom));
                log.message(INFO, "acceptForSelf add a new connection success, fd: %d", connfd);

                cnt--;
                int m = ::write(efd, &cnt, sizeof(cnt));
                if(m < 0)
                {
                    log.message(INFO, "acceptForSelf efd write error, errno: %d", errno);
                }
            }
            else
            {
                if(errno == EAGAIN) break; //数据取尽，无数据就绪
                else if(errno == EINTR) continue; //上次读取被信号中断
                else //发生错误
                {
                    log.message(INFO, "acceptForSelf efd read error, errno: %d", errno);
                    break;
                }
            }
        }
    }

    static void acceptForSubReactor(Connection* conn)
    {
        errno = 0;
        while(true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int connfd = ::accept(conn->getSockFd(), (struct sockaddr*)&peer, &len);
            if(connfd > 0)
            {
                int efd = conn->_reactorFrom->getEfd();
                conn->_reactorFrom->pushEventQueue(connfd);
                uint64_t one = 1;
                int n = ::write(efd, &one, sizeof(one));
                if(n < 0)
                {
                    log.message(INFO, "acceptForSubReactor efd write error, errno: %d", errno);
                }
            }
            else
            {
                if(errno == EAGAIN) break; //数据取尽，无数据就绪
                else if(errno == EINTR) continue; //上次读取被信号中断
                else //发生错误
                {
                    log.message(WARN, "acceptForSubReactor error... %d: %s", errno, strerror(errno));
                    break;
                }
            }
        }
    }

    static void handlerRequest(Connection* conn)
    {
        std::string& inBuffer = conn->getInBuffer();
        std::string content;
        DLP::ReqRespFactory factory;
        CalculateService calculateService;
        while(DLP::dlpDecoding(inBuffer, content))
        {
            std::shared_ptr<DLP::Request> req = factory.makeRequest();
            if(req->deserialize(content)) 
            {
                int code = -1;
                int result = calculateService.doCalculate(req->getX(), req->getY(), req->getOp(), code);
                std::shared_ptr<DLP::Response> resp = factory.makeResponse(result, code);
                std::string dlpResponse = DLP::dlpEncoding(resp->serialize());
                conn->appendOutBuffer(dlpResponse);
            }
        }
        if(!conn->isOutBufferEmpty())
        {
            write(conn);
        }
    }

    static void read(Connection* conn)
    {
        errno = 0;
        char buffer[1024];
        while(true)
        {
            // 只负责把本轮数据读尽，不关心数据的格式/协议
            ssize_t n = ::read(conn->getSockFd(), buffer, sizeof(buffer)-1);
            if(n > 0)
            {
                buffer[n] = '\0';
                conn->appendInBuffer(buffer);
            }
            else
            {
                if(errno == EAGAIN) break; //数据取尽，无数据就绪
                else if(errno == EINTR) continue; //上次读取被信号中断
                else //发生错误 / 客户端正常退出，连接关闭，属于读事件就绪，::read返回0
                {
                    except(conn);
                    log.message(WARN, "EventHandler::read error... %d: %s", errno, strerror(errno));
                    return;
                }
            }
        }
        std::cout << "fd# " << conn->getSockFd() << std::endl << "接收缓冲区：" << conn->getInBuffer() << std::endl;
        // EAGAIN
        handlerRequest(conn);
    }

    static void write(Connection* conn)
    {
        errno = 0;
        std::string& outBuffer = conn->getOutBuffer();
        while(true)
        {
            ssize_t n = ::write(conn->getSockFd(), outBuffer.c_str(), outBuffer.size());
            if(n > 0)
            {
                outBuffer.erase(0, n); //已经发送的，从缓冲区移除
                if(outBuffer.empty()) break;
            }
            else
            {
                if(errno == EAGAIN) break;
                else if(errno == EINTR) continue;
                else
                {
                    except(conn);
                    log.message(WARN, "EventHandler::write error... %d: %s", errno, strerror(errno));
                    return;
                }
            }
        }

        if(conn->isOutBufferEmpty())
        {
            conn->_reactorFrom->enableEvent(conn->getSockFd(), true, false);
        }
        else
        {
            conn->_reactorFrom->enableEvent(conn->getSockFd(), true, true);
        }
    }

    static void except(Connection* conn)
    {
        log.message(INFO, "EventHandler::except, connection erase, fd: %d", conn->getSockFd());
        conn->_reactorFrom->removeConnection(conn);
        conn->closeFd();
        delete conn;
    }

    ~EventHandler()
    {}
};